home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkCanvPoly.c < prev    next >
C/C++ Source or Header  |  1995-06-27  |  29KB  |  986 lines

  1. /* 
  2.  * tkCanvPoly.c --
  3.  *
  4.  *    This file implements polygon items for canvas widgets.
  5.  *
  6.  * Copyright (c) 1991-1994 The Regents of the University of California.
  7.  * Copyright (c) 1994 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  */
  12.  
  13. static char sccsid[] = "@(#) tkCanvPoly.c 1.28 95/06/12 08:27:14";
  14.  
  15. #include <stdio.h>
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18.  
  19. /*
  20.  * The structure below defines the record for each polygon item.
  21.  */
  22.  
  23. typedef struct PolygonItem  {
  24.     Tk_Item header;        /* Generic stuff that's the same for all
  25.                  * types.  MUST BE FIRST IN STRUCTURE. */
  26.     int numPoints;        /* Number of points in polygon (always >= 3).
  27.                  * Polygon is always closed. */
  28.     int pointsAllocated;    /* Number of points for which space is
  29.                  * allocated at *coordPtr. */
  30.     double *coordPtr;        /* Pointer to malloc-ed array containing
  31.                  * x- and y-coords of all points in polygon.
  32.                  * X-coords are even-valued indices, y-coords
  33.                  * are corresponding odd-valued indices. */
  34.     int width;            /* Width of outline. */
  35.     XColor *outlineColor;    /* Color for outline. */
  36.     GC outlineGC;        /* Graphics context for drawing outline. */
  37.     XColor *fillColor;        /* Foreground color for polygon. */
  38.     Pixmap fillStipple;        /* Stipple bitmap for filling polygon. */
  39.     GC fillGC;            /* Graphics context for filling polygon. */
  40.     int smooth;            /* Non-zero means draw shape smoothed (i.e.
  41.                  * with Bezier splines). */
  42.     int splineSteps;        /* Number of steps in each spline segment. */
  43. } PolygonItem;
  44.  
  45. /*
  46.  * Information used for parsing configuration specs:
  47.  */
  48.  
  49. static Tk_ConfigSpec configSpecs[] = {
  50.     {TK_CONFIG_COLOR, "-fill", (char *) NULL, (char *) NULL,
  51.     "black", Tk_Offset(PolygonItem, fillColor), TK_CONFIG_NULL_OK},
  52.     {TK_CONFIG_COLOR, "-outline", (char *) NULL, (char *) NULL,
  53.     (char *) NULL, Tk_Offset(PolygonItem, outlineColor), TK_CONFIG_NULL_OK},
  54.     {TK_CONFIG_BOOLEAN, "-smooth", (char *) NULL, (char *) NULL,
  55.     "0", Tk_Offset(PolygonItem, smooth), TK_CONFIG_DONT_SET_DEFAULT},
  56.     {TK_CONFIG_INT, "-splinesteps", (char *) NULL, (char *) NULL,
  57.     "12", Tk_Offset(PolygonItem, splineSteps), TK_CONFIG_DONT_SET_DEFAULT},
  58.     {TK_CONFIG_BITMAP, "-stipple", (char *) NULL, (char *) NULL,
  59.     (char *) NULL, Tk_Offset(PolygonItem, fillStipple), TK_CONFIG_NULL_OK},
  60.     {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL,
  61.     (char *) NULL, 0, TK_CONFIG_NULL_OK, &tk_CanvasTagsOption},
  62.     {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL,
  63.     "1", Tk_Offset(PolygonItem, width), TK_CONFIG_DONT_SET_DEFAULT},
  64.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  65.     (char *) NULL, 0, 0}
  66. };
  67.  
  68. /*
  69.  * Prototypes for procedures defined in this file:
  70.  */
  71.  
  72. static void        ComputePolygonBbox _ANSI_ARGS_((Tk_Canvas canvas,
  73.                 PolygonItem *polyPtr));
  74. static int        ConfigurePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  75.                 Tk_Canvas canvas, Tk_Item *itemPtr, int argc,
  76.                 char **argv, int flags));
  77. static int        CreatePolygon _ANSI_ARGS_((Tcl_Interp *interp,
  78.                 Tk_Canvas canvas, struct Tk_Item *itemPtr,
  79.                 int argc, char **argv));
  80. static void        DeletePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  81.                 Tk_Item *itemPtr,  Display *display));
  82. static void        DisplayPolygon _ANSI_ARGS_((Tk_Canvas canvas,
  83.                 Tk_Item *itemPtr, Display *display, Drawable dst,
  84.                 int x, int y, int width, int height));
  85. static int        PolygonCoords _ANSI_ARGS_((Tcl_Interp *interp,
  86.                 Tk_Canvas canvas, Tk_Item *itemPtr,
  87.                 int argc, char **argv));
  88. static int        PolygonToArea _ANSI_ARGS_((Tk_Canvas canvas,
  89.                 Tk_Item *itemPtr, double *rectPtr));
  90. static double        PolygonToPoint _ANSI_ARGS_((Tk_Canvas canvas,
  91.                 Tk_Item *itemPtr, double *pointPtr));
  92. static int        PolygonToPostscript _ANSI_ARGS_((Tcl_Interp *interp,
  93.                 Tk_Canvas canvas, Tk_Item *itemPtr, int prepass));
  94. static void        ScalePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  95.                 Tk_Item *itemPtr, double originX, double originY,
  96.                 double scaleX, double scaleY));
  97. static void        TranslatePolygon _ANSI_ARGS_((Tk_Canvas canvas,
  98.                 Tk_Item *itemPtr, double deltaX, double deltaY));
  99.  
  100. /*
  101.  * The structures below defines the polygon item type by means
  102.  * of procedures that can be invoked by generic item code.
  103.  */
  104.  
  105. Tk_ItemType tkPolygonType = {
  106.     "polygon",                /* name */
  107.     sizeof(PolygonItem),        /* itemSize */
  108.     CreatePolygon,            /* createProc */
  109.     configSpecs,            /* configSpecs */
  110.     ConfigurePolygon,            /* configureProc */
  111.     PolygonCoords,            /* coordProc */
  112.     DeletePolygon,            /* deleteProc */
  113.     DisplayPolygon,            /* displayProc */
  114.     0,                    /* alwaysRedraw */
  115.     PolygonToPoint,            /* pointProc */
  116.     PolygonToArea,            /* areaProc */
  117.     PolygonToPostscript,        /* postscriptProc */
  118.     ScalePolygon,            /* scaleProc */
  119.     TranslatePolygon,            /* translateProc */
  120.     (Tk_ItemIndexProc *) NULL,        /* indexProc */
  121.     (Tk_ItemCursorProc *) NULL,        /* icursorProc */
  122.     (Tk_ItemSelectionProc *) NULL,    /* selectionProc */
  123.     (Tk_ItemInsertProc *) NULL,        /* insertProc */
  124.     (Tk_ItemDCharsProc *) NULL,        /* dTextProc */
  125.     (Tk_ItemType *) NULL        /* nextPtr */
  126. };
  127.  
  128. /*
  129.  * The definition below determines how large are static arrays
  130.  * used to hold spline points (splines larger than this have to
  131.  * have their arrays malloc-ed).
  132.  */
  133.  
  134. #define MAX_STATIC_POINTS 200
  135.  
  136. /*
  137.  *--------------------------------------------------------------
  138.  *
  139.  * CreatePolygon --
  140.  *
  141.  *    This procedure is invoked to create a new polygon item in
  142.  *    a canvas.
  143.  *
  144.  * Results:
  145.  *    A standard Tcl return value.  If an error occurred in
  146.  *    creating the item, then an error message is left in
  147.  *    interp->result;  in this case itemPtr is
  148.  *    left uninitialized, so it can be safely freed by the
  149.  *    caller.
  150.  *
  151.  * Side effects:
  152.  *    A new polygon item is created.
  153.  *
  154.  *--------------------------------------------------------------
  155.  */
  156.  
  157. static int
  158. CreatePolygon(interp, canvas, itemPtr, argc, argv)
  159.     Tcl_Interp *interp;            /* Interpreter for error reporting. */
  160.     Tk_Canvas canvas;            /* Canvas to hold new item. */
  161.     Tk_Item *itemPtr;            /* Record to hold new item;  header
  162.                      * has been initialized by caller. */
  163.     int argc;                /* Number of arguments in argv. */
  164.     char **argv;            /* Arguments describing polygon. */
  165. {
  166.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  167.     int i;
  168.  
  169.     if (argc < 6) {
  170.     Tcl_AppendResult(interp, "wrong # args:  should be \"",
  171.         Tk_PathName(Tk_CanvasTkwin(canvas)), "\" create ",
  172.         itemPtr->typePtr->name,
  173.         " x1 y1 x2 y2 x3 y3 ?x4 y4 ...? ?options?", (char *) NULL);
  174.     return TCL_ERROR;
  175.     }
  176.  
  177.     /*
  178.      * Carry out initialization that is needed in order to clean
  179.      * up after errors during the the remainder of this procedure.
  180.      */
  181.  
  182.     polyPtr->numPoints = 0;
  183.     polyPtr->pointsAllocated = 0;
  184.     polyPtr->coordPtr = NULL;
  185.     polyPtr->width = 1;
  186.     polyPtr->outlineColor = NULL;
  187.     polyPtr->outlineGC = None;
  188.     polyPtr->fillColor = NULL;
  189.     polyPtr->fillStipple = None;
  190.     polyPtr->fillGC = None;
  191.     polyPtr->smooth = 0;
  192.     polyPtr->splineSteps = 12;
  193.  
  194.     /*
  195.      * Count the number of points and then parse them into a point
  196.      * array.  Leading arguments are assumed to be points if they
  197.      * start with a digit or a minus sign followed by a digit.
  198.      */
  199.  
  200.     for (i = 4; i < (argc-1); i+=2) {
  201.     if ((!isdigit(UCHAR(argv[i][0]))) &&
  202.         ((argv[i][0] != '-') || (!isdigit(UCHAR(argv[i][1]))))) {
  203.         break;
  204.     }
  205.     }
  206.     if (PolygonCoords(interp, canvas, itemPtr, i, argv) != TCL_OK) {
  207.     goto error;
  208.     }
  209.  
  210.     if (ConfigurePolygon(interp, canvas, itemPtr, argc-i, argv+i, 0)
  211.         == TCL_OK) {
  212.     return TCL_OK;
  213.     }
  214.  
  215.     error:
  216.     DeletePolygon(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas)));
  217.     return TCL_ERROR;
  218. }
  219.  
  220. /*
  221.  *--------------------------------------------------------------
  222.  *
  223.  * PolygonCoords --
  224.  *
  225.  *    This procedure is invoked to process the "coords" widget
  226.  *    command on polygons.  See the user documentation for details
  227.  *    on what it does.
  228.  *
  229.  * Results:
  230.  *    Returns TCL_OK or TCL_ERROR, and sets interp->result.
  231.  *
  232.  * Side effects:
  233.  *    The coordinates for the given item may be changed.
  234.  *
  235.  *--------------------------------------------------------------
  236.  */
  237.  
  238. static int
  239. PolygonCoords(interp, canvas, itemPtr, argc, argv)
  240.     Tcl_Interp *interp;            /* Used for error reporting. */
  241.     Tk_Canvas canvas;            /* Canvas containing item. */
  242.     Tk_Item *itemPtr;            /* Item whose coordinates are to be
  243.                      * read or modified. */
  244.     int argc;                /* Number of coordinates supplied in
  245.                      * argv. */
  246.     char **argv;            /* Array of coordinates: x1, y1,
  247.                      * x2, y2, ... */
  248. {
  249.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  250.     char buffer[TCL_DOUBLE_SPACE];
  251.     int i, numPoints;
  252.  
  253.     if (argc == 0) {
  254.     for (i = 0; i < 2*polyPtr->numPoints; i++) {
  255.         Tcl_PrintDouble(interp, polyPtr->coordPtr[i], buffer);
  256.         Tcl_AppendElement(interp, buffer);
  257.     }
  258.     } else if (argc < 6) {
  259.     Tcl_AppendResult(interp,
  260.         "too few coordinates for polygon:  must have at least 6",
  261.         (char *) NULL);
  262.     return TCL_ERROR;
  263.     } else if (argc & 1) {
  264.     Tcl_AppendResult(interp,
  265.         "odd number of coordinates specified for polygon",
  266.         (char *) NULL);
  267.     return TCL_ERROR;
  268.     } else {
  269.     numPoints = argc/2;
  270.     if (polyPtr->pointsAllocated <= numPoints) {
  271.         if (polyPtr->coordPtr != NULL) {
  272.         ckfree((char *) polyPtr->coordPtr);
  273.         }
  274.  
  275.         /*
  276.          * One extra point gets allocated here, just in case we have
  277.          * to add another point to close the polygon.
  278.          */
  279.  
  280.         polyPtr->coordPtr = (double *) ckalloc((unsigned)
  281.             (sizeof(double) * (argc+2)));
  282.         polyPtr->pointsAllocated = numPoints+1;
  283.     }
  284.     for (i = argc-1; i >= 0; i--) {
  285.         if (Tk_CanvasGetCoord(interp, canvas, argv[i],
  286.             &polyPtr->coordPtr[i]) != TCL_OK) {
  287.         return TCL_ERROR;
  288.         }
  289.     }
  290.     polyPtr->numPoints = numPoints;
  291.     
  292.     /*
  293.      * Close the polygon if it isn't already closed.
  294.      */
  295.     
  296.     if ((polyPtr->coordPtr[argc-2] != polyPtr->coordPtr[0])
  297.         || (polyPtr->coordPtr[argc-1] != polyPtr->coordPtr[1])) {
  298.         polyPtr->numPoints++;
  299.         polyPtr->coordPtr[argc] = polyPtr->coordPtr[0];
  300.         polyPtr->coordPtr[argc+1] = polyPtr->coordPtr[1];
  301.     }
  302.     ComputePolygonBbox(canvas, polyPtr);
  303.     }
  304.     return TCL_OK;
  305. }
  306.  
  307. /*
  308.  *--------------------------------------------------------------
  309.  *
  310.  * ConfigurePolygon --
  311.  *
  312.  *    This procedure is invoked to configure various aspects
  313.  *    of a polygon item such as its background color.
  314.  *
  315.  * Results:
  316.  *    A standard Tcl result code.  If an error occurs, then
  317.  *    an error message is left in interp->result.
  318.  *
  319.  * Side effects:
  320.  *    Configuration information, such as colors and stipple
  321.  *    patterns, may be set for itemPtr.
  322.  *
  323.  *--------------------------------------------------------------
  324.  */
  325.  
  326. static int
  327. ConfigurePolygon(interp, canvas, itemPtr, argc, argv, flags)
  328.     Tcl_Interp *interp;        /* Interpreter for error reporting. */
  329.     Tk_Canvas canvas;        /* Canvas containing itemPtr. */
  330.     Tk_Item *itemPtr;        /* Polygon item to reconfigure. */
  331.     int argc;            /* Number of elements in argv.  */
  332.     char **argv;        /* Arguments describing things to configure. */
  333.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  334. {
  335.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  336.     XGCValues gcValues;
  337.     GC newGC;
  338.     unsigned long mask;
  339.     Tk_Window tkwin;
  340.  
  341.     tkwin = Tk_CanvasTkwin(canvas);
  342.     if (Tk_ConfigureWidget(interp, tkwin, configSpecs, argc, argv,
  343.         (char *) polyPtr, flags) != TCL_OK) {
  344.     return TCL_ERROR;
  345.     }
  346.  
  347.     /*
  348.      * A few of the options require additional processing, such as
  349.      * graphics contexts.
  350.      */
  351.  
  352.     if (polyPtr->width < 1) {
  353.     polyPtr->width = 1;
  354.     }
  355.     if (polyPtr->outlineColor == NULL) {
  356.     newGC = None;
  357.     } else {
  358.     gcValues.foreground = polyPtr->outlineColor->pixel;
  359.     gcValues.line_width = polyPtr->width;
  360.     gcValues.cap_style = CapRound;
  361.     gcValues.join_style = JoinRound;
  362.     mask = GCForeground|GCLineWidth|GCCapStyle|GCJoinStyle;
  363.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  364.     }
  365.     if (polyPtr->outlineGC != None) {
  366.     Tk_FreeGC(Tk_Display(tkwin), polyPtr->outlineGC);
  367.     }
  368.     polyPtr->outlineGC = newGC;
  369.  
  370.     if (polyPtr->fillColor == NULL) {
  371.     newGC = None;
  372.     } else {
  373.     gcValues.foreground = polyPtr->fillColor->pixel;
  374.     mask = GCForeground;
  375.     if (polyPtr->fillStipple != None) {
  376.         gcValues.stipple = polyPtr->fillStipple;
  377.         gcValues.fill_style = FillStippled;
  378.         mask |= GCStipple|GCFillStyle;
  379.     }
  380.     newGC = Tk_GetGC(tkwin, mask, &gcValues);
  381.     }
  382.     if (polyPtr->fillGC != None) {
  383.     Tk_FreeGC(Tk_Display(tkwin), polyPtr->fillGC);
  384.     }
  385.     polyPtr->fillGC = newGC;
  386.  
  387.     /*
  388.      * Keep spline parameters within reasonable limits.
  389.      */
  390.  
  391.     if (polyPtr->splineSteps < 1) {
  392.     polyPtr->splineSteps = 1;
  393.     } else if (polyPtr->splineSteps > 100) {
  394.     polyPtr->splineSteps = 100;
  395.     }
  396.  
  397.     ComputePolygonBbox(canvas, polyPtr);
  398.     return TCL_OK;
  399. }
  400.  
  401. /*
  402.  *--------------------------------------------------------------
  403.  *
  404.  * DeletePolygon --
  405.  *
  406.  *    This procedure is called to clean up the data structure
  407.  *    associated with a polygon item.
  408.  *
  409.  * Results:
  410.  *    None.
  411.  *
  412.  * Side effects:
  413.  *    Resources associated with itemPtr are released.
  414.  *
  415.  *--------------------------------------------------------------
  416.  */
  417.  
  418. static void
  419. DeletePolygon(canvas, itemPtr, display)
  420.     Tk_Canvas canvas;            /* Info about overall canvas widget. */
  421.     Tk_Item *itemPtr;            /* Item that is being deleted. */
  422.     Display *display;            /* Display containing window for
  423.                      * canvas. */
  424. {
  425.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  426.  
  427.     if (polyPtr->coordPtr != NULL) {
  428.     ckfree((char *) polyPtr->coordPtr);
  429.     }
  430.     if (polyPtr->fillColor != NULL) {
  431.     Tk_FreeColor(polyPtr->fillColor);
  432.     }
  433.     if (polyPtr->fillStipple != None) {
  434.     Tk_FreeBitmap(display, polyPtr->fillStipple);
  435.     }
  436.     if (polyPtr->outlineColor != NULL) {
  437.     Tk_FreeColor(polyPtr->outlineColor);
  438.     }
  439.     if (polyPtr->outlineGC != None) {
  440.     Tk_FreeGC(display, polyPtr->outlineGC);
  441.     }
  442.     if (polyPtr->fillGC != None) {
  443.     Tk_FreeGC(display, polyPtr->fillGC);
  444.     }
  445. }
  446.  
  447. /*
  448.  *--------------------------------------------------------------
  449.  *
  450.  * ComputePolygonBbox --
  451.  *
  452.  *    This procedure is invoked to compute the bounding box of
  453.  *    all the pixels that may be drawn as part of a polygon.
  454.  *
  455.  * Results:
  456.  *    None.
  457.  *
  458.  * Side effects:
  459.  *    The fields x1, y1, x2, and y2 are updated in the header
  460.  *    for itemPtr.
  461.  *
  462.  *--------------------------------------------------------------
  463.  */
  464.  
  465. static void
  466. ComputePolygonBbox(canvas, polyPtr)
  467.     Tk_Canvas canvas;            /* Canvas that contains item. */
  468.     PolygonItem *polyPtr;        /* Item whose bbox is to be
  469.                      * recomputed. */
  470. {
  471.     double *coordPtr;
  472.     int i;
  473.  
  474.     coordPtr = polyPtr->coordPtr;
  475.     polyPtr->header.x1 = polyPtr->header.x2 = *coordPtr;
  476.     polyPtr->header.y1 = polyPtr->header.y2 = coordPtr[1];
  477.  
  478.     for (i = 1, coordPtr = polyPtr->coordPtr+2; i < polyPtr->numPoints;
  479.         i++, coordPtr += 2) {
  480.     TkIncludePoint((Tk_Item *) polyPtr, coordPtr);
  481.     }
  482.  
  483.     /*
  484.      * Expand bounding box in all directions to account for the outline,
  485.      * which can stick out beyond the polygon.  Add one extra pixel of
  486.      * fudge, just in case X rounds differently than we do.
  487.      */
  488.  
  489.     i = (polyPtr->width+1)/2 + 1;
  490.     polyPtr->header.x1 -= i;
  491.     polyPtr->header.x2 += i;
  492.     polyPtr->header.y1 -= i;
  493.     polyPtr->header.y2 += i;
  494. }
  495.  
  496. /*
  497.  *--------------------------------------------------------------
  498.  *
  499.  * TkFillPolygon --
  500.  *
  501.  *    This procedure is invoked to convert a polygon to screen
  502.  *    coordinates and display it using a particular GC.
  503.  *
  504.  * Results:
  505.  *    None.
  506.  *
  507.  * Side effects:
  508.  *    ItemPtr is drawn in drawable using the transformation
  509.  *    information in canvas.
  510.  *
  511.  *--------------------------------------------------------------
  512.  */
  513.  
  514. void
  515. TkFillPolygon(canvas, coordPtr, numPoints, display, drawable, gc, outlineGC)
  516.     Tk_Canvas canvas;            /* Canvas whose coordinate system
  517.                      * is to be used for drawing. */
  518.     double *coordPtr;            /* Array of coordinates for polygon:
  519.                      * x1, y1, x2, y2, .... */
  520.     int numPoints;            /* Twice this many coordinates are
  521.                      * present at *coordPtr. */
  522.     Display *display;            /* Display on which to draw polygon. */
  523.     Drawable drawable;            /* Pixmap or window in which to draw
  524.                      * polygon. */
  525.     GC gc;                /* Graphics context for drawing. */
  526.     GC outlineGC;            /* If not None, use this to draw an
  527.                      * outline around the polygon after
  528.                      * filling it. */
  529. {
  530.     XPoint staticPoints[MAX_STATIC_POINTS];
  531.     XPoint *pointPtr;
  532.     XPoint *pPtr;
  533.     int i;
  534.  
  535.     /*
  536.      * Build up an array of points in screen coordinates.  Use a
  537.      * static array unless the polygon has an enormous number of points;
  538.      * in this case, dynamically allocate an array.
  539.      */
  540.  
  541.     if (numPoints <= MAX_STATIC_POINTS) {
  542.     pointPtr = staticPoints;
  543.     } else {
  544.     pointPtr = (XPoint *) ckalloc((unsigned) (numPoints * sizeof(XPoint)));
  545.     }
  546.  
  547.     for (i = 0, pPtr = pointPtr; i < numPoints; i += 1, coordPtr += 2, pPtr++) {
  548.     Tk_CanvasDrawableCoords(canvas, coordPtr[0], coordPtr[1], &pPtr->x,
  549.         &pPtr->y);
  550.     }
  551.  
  552.     /*
  553.      * Display polygon, then free up polygon storage if it was dynamically
  554.      * allocated.
  555.      */
  556.  
  557.     if (gc != None) {
  558.     XFillPolygon(display, drawable, gc, pointPtr, numPoints, Complex,
  559.         CoordModeOrigin);
  560.     }
  561.     if (outlineGC != None) {
  562.     XDrawLines(display, drawable, outlineGC, pointPtr,
  563.         numPoints, CoordModeOrigin);
  564.     }
  565.     if (pointPtr != staticPoints) {
  566.     ckfree((char *) pointPtr);
  567.     }
  568. }
  569.  
  570. /*
  571.  *--------------------------------------------------------------
  572.  *
  573.  * DisplayPolygon --
  574.  *
  575.  *    This procedure is invoked to draw a polygon item in a given
  576.  *    drawable.
  577.  *
  578.  * Results:
  579.  *    None.
  580.  *
  581.  * Side effects:
  582.  *    ItemPtr is drawn in drawable using the transformation
  583.  *    information in canvas.
  584.  *
  585.  *--------------------------------------------------------------
  586.  */
  587.  
  588. static void
  589. DisplayPolygon(canvas, itemPtr, display, drawable, x, y, width, height)
  590.     Tk_Canvas canvas;            /* Canvas that contains item. */
  591.     Tk_Item *itemPtr;            /* Item to be displayed. */
  592.     Display *display;            /* Display on which to draw item. */
  593.     Drawable drawable;            /* Pixmap or window in which to draw
  594.                      * item. */
  595.     int x, y, width, height;        /* Describes region of canvas that
  596.                      * must be redisplayed (not used). */
  597. {
  598.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  599.  
  600.     if ((polyPtr->fillGC == None) && (polyPtr->outlineGC == None)) {
  601.     return;
  602.     }
  603.  
  604.     /*
  605.      * If we're stippling then modify the stipple offset in the GC.  Be
  606.      * sure to reset the offset when done, since the GC is supposed to be
  607.      * read-only.
  608.      */
  609.  
  610.     if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
  611.     Tk_CanvasSetStippleOrigin(canvas, polyPtr->fillGC);
  612.     }
  613.  
  614.     if (!polyPtr->smooth) {
  615.     TkFillPolygon(canvas, polyPtr->coordPtr, polyPtr->numPoints,
  616.         display, drawable, polyPtr->fillGC, polyPtr->outlineGC);
  617.     } else {
  618.     int numPoints;
  619.     XPoint staticPoints[MAX_STATIC_POINTS];
  620.     XPoint *pointPtr;
  621.  
  622.     /*
  623.      * This is a smoothed polygon.  Display using a set of generated
  624.      * spline points rather than the original points.
  625.      */
  626.  
  627.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  628.     if (numPoints <= MAX_STATIC_POINTS) {
  629.         pointPtr = staticPoints;
  630.     } else {
  631.         pointPtr = (XPoint *) ckalloc((unsigned)
  632.             (numPoints * sizeof(XPoint)));
  633.     }
  634.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  635.         polyPtr->numPoints, polyPtr->splineSteps, pointPtr,
  636.         (double *) NULL);
  637.     if (polyPtr->fillGC != None) {
  638.         XFillPolygon(display, drawable, polyPtr->fillGC, pointPtr,
  639.             numPoints, Complex, CoordModeOrigin);
  640.     }
  641.     if (polyPtr->outlineGC != None) {
  642.         XDrawLines(display, drawable, polyPtr->outlineGC, pointPtr,
  643.             numPoints, CoordModeOrigin);
  644.     }
  645.     if (pointPtr != staticPoints) {
  646.         ckfree((char *) pointPtr);
  647.     }
  648.     }
  649.     if ((polyPtr->fillStipple != None) && (polyPtr->fillGC != None)) {
  650.     XSetTSOrigin(display, polyPtr->fillGC, 0, 0);
  651.     }
  652. }
  653.  
  654. /*
  655.  *--------------------------------------------------------------
  656.  *
  657.  * PolygonToPoint --
  658.  *
  659.  *    Computes the distance from a given point to a given
  660.  *    polygon, in canvas units.
  661.  *
  662.  * Results:
  663.  *    The return value is 0 if the point whose x and y coordinates
  664.  *    are pointPtr[0] and pointPtr[1] is inside the polygon.  If the
  665.  *    point isn't inside the polygon then the return value is the
  666.  *    distance from the point to the polygon.
  667.  *
  668.  * Side effects:
  669.  *    None.
  670.  *
  671.  *--------------------------------------------------------------
  672.  */
  673.  
  674.     /* ARGSUSED */
  675. static double
  676. PolygonToPoint(canvas, itemPtr, pointPtr)
  677.     Tk_Canvas canvas;        /* Canvas containing item. */
  678.     Tk_Item *itemPtr;        /* Item to check against point. */
  679.     double *pointPtr;        /* Pointer to x and y coordinates. */
  680. {
  681.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  682.     double *coordPtr, distance;
  683.     double staticSpace[2*MAX_STATIC_POINTS];
  684.     int numPoints;
  685.  
  686.     if (!polyPtr->smooth) {
  687.     distance = TkPolygonToPoint(polyPtr->coordPtr, polyPtr->numPoints,
  688.         pointPtr);
  689.     } else {
  690.     /*
  691.      * Smoothed polygon.  Generate a new set of points and use them
  692.      * for comparison.
  693.      */
  694.     
  695.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  696.     if (numPoints <= MAX_STATIC_POINTS) {
  697.         coordPtr = staticSpace;
  698.     } else {
  699.         coordPtr = (double *) ckalloc((unsigned)
  700.             (2*numPoints*sizeof(double)));
  701.     }
  702.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  703.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  704.         coordPtr);
  705.     distance = TkPolygonToPoint(coordPtr, numPoints, pointPtr);
  706.     if (coordPtr != staticSpace) {
  707.         ckfree((char *) coordPtr);
  708.     }
  709.     }
  710.     if (polyPtr->outlineColor != NULL) {
  711.     distance -= polyPtr->width/2.0;
  712.     if (distance < 0) {
  713.         distance = 0;
  714.     }
  715.     }
  716.     return distance;
  717. }
  718.  
  719. /*
  720.  *--------------------------------------------------------------
  721.  *
  722.  * PolygonToArea --
  723.  *
  724.  *    This procedure is called to determine whether an item
  725.  *    lies entirely inside, entirely outside, or overlapping
  726.  *    a given rectangular area.
  727.  *
  728.  * Results:
  729.  *    -1 is returned if the item is entirely outside the area
  730.  *    given by rectPtr, 0 if it overlaps, and 1 if it is entirely
  731.  *    inside the given area.
  732.  *
  733.  * Side effects:
  734.  *    None.
  735.  *
  736.  *--------------------------------------------------------------
  737.  */
  738.  
  739.     /* ARGSUSED */
  740. static int
  741. PolygonToArea(canvas, itemPtr, rectPtr)
  742.     Tk_Canvas canvas;        /* Canvas containing item. */
  743.     Tk_Item *itemPtr;        /* Item to check against polygon. */
  744.     double *rectPtr;        /* Pointer to array of four coordinates
  745.                  * (x1, y1, x2, y2) describing rectangular
  746.                  * area.  */
  747. {
  748.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  749.     double *coordPtr, rect2[4], halfWidth;
  750.     double staticSpace[2*MAX_STATIC_POINTS];
  751.     int numPoints, result;
  752.  
  753.     /*
  754.      * Handle smoothed polygons by generating an expanded set of points
  755.      * against which to do the check.
  756.      */
  757.  
  758.     if (polyPtr->smooth) {
  759.     numPoints = 1 + polyPtr->numPoints*polyPtr->splineSteps;
  760.     if (numPoints <= MAX_STATIC_POINTS) {
  761.         coordPtr = staticSpace;
  762.     } else {
  763.         coordPtr = (double *) ckalloc((unsigned)
  764.             (2*numPoints*sizeof(double)));
  765.     }
  766.     numPoints = TkMakeBezierCurve(canvas, polyPtr->coordPtr,
  767.         polyPtr->numPoints, polyPtr->splineSteps, (XPoint *) NULL,
  768.         coordPtr);
  769.     } else {
  770.     numPoints = polyPtr->numPoints;
  771.     coordPtr = polyPtr->coordPtr;
  772.     }
  773.  
  774.     if (polyPtr->width <= 1) {
  775.     /*
  776.      * The outline of the polygon doesn't stick out, so we can
  777.      * do a simple check.
  778.      */
  779.  
  780.     result = TkPolygonToArea(coordPtr, numPoints, rectPtr);
  781.     } else {
  782.     /*
  783.      * The polygon has a wide outline, so the check is more complicated.
  784.      * First, check the line segments to see if they overlap the area.
  785.      */
  786.  
  787.     result = TkThickPolyLineToArea(coordPtr, numPoints, 
  788.         (double) polyPtr->width, CapRound, JoinRound, rectPtr);
  789.     if (result >= 0) {
  790.         goto done;
  791.     }
  792.  
  793.     /*
  794.      * There is no overlap between the polygon's outline and the
  795.      * rectangle.  This means either the rectangle is entirely outside
  796.      * the polygon or entirely inside.  To tell the difference,
  797.      * see whether the polygon (with 0 outline width) overlaps the
  798.      * rectangle bloated by half the outline width.
  799.      */
  800.  
  801.     halfWidth = polyPtr->width/2.0;
  802.     rect2[0] = rectPtr[0] - halfWidth;
  803.     rect2[1] = rectPtr[1] - halfWidth;
  804.     rect2[2] = rectPtr[2] + halfWidth;
  805.     rect2[3] = rectPtr[3] + halfWidth;
  806.     if (TkPolygonToArea(coordPtr, numPoints, rect2) == -1) {
  807.         result = -1;
  808.     } else {
  809.         result = 0;
  810.     }
  811.     }
  812.  
  813.     done:
  814.     if ((coordPtr != staticSpace) && (coordPtr != polyPtr->coordPtr)) {
  815.     ckfree((char *) coordPtr);
  816.     }
  817.     return result;
  818. }
  819.  
  820. /*
  821.  *--------------------------------------------------------------
  822.  *
  823.  * ScalePolygon --
  824.  *
  825.  *    This procedure is invoked to rescale a polygon item.
  826.  *
  827.  * Results:
  828.  *    None.
  829.  *
  830.  * Side effects:
  831.  *    The polygon referred to by itemPtr is rescaled so that the
  832.  *    following transformation is applied to all point
  833.  *    coordinates:
  834.  *        x' = originX + scaleX*(x-originX)
  835.  *        y' = originY + scaleY*(y-originY)
  836.  *
  837.  *--------------------------------------------------------------
  838.  */
  839.  
  840. static void
  841. ScalePolygon(canvas, itemPtr, originX, originY, scaleX, scaleY)
  842.     Tk_Canvas canvas;            /* Canvas containing polygon. */
  843.     Tk_Item *itemPtr;            /* Polygon to be scaled. */
  844.     double originX, originY;        /* Origin about which to scale rect. */
  845.     double scaleX;            /* Amount to scale in X direction. */
  846.     double scaleY;            /* Amount to scale in Y direction. */
  847. {
  848.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  849.     double *coordPtr;
  850.     int i;
  851.  
  852.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  853.         i++, coordPtr += 2) {
  854.     *coordPtr = originX + scaleX*(*coordPtr - originX);
  855.     coordPtr[1] = originY + scaleY*(coordPtr[1] - originY);
  856.     }
  857.     ComputePolygonBbox(canvas, polyPtr);
  858. }
  859.  
  860. /*
  861.  *--------------------------------------------------------------
  862.  *
  863.  * TranslatePolygon --
  864.  *
  865.  *    This procedure is called to move a polygon by a given
  866.  *    amount.
  867.  *
  868.  * Results:
  869.  *    None.
  870.  *
  871.  * Side effects:
  872.  *    The position of the polygon is offset by (xDelta, yDelta),
  873.  *    and the bounding box is updated in the generic part of the
  874.  *    item structure.
  875.  *
  876.  *--------------------------------------------------------------
  877.  */
  878.  
  879. static void
  880. TranslatePolygon(canvas, itemPtr, deltaX, deltaY)
  881.     Tk_Canvas canvas;            /* Canvas containing item. */
  882.     Tk_Item *itemPtr;            /* Item that is being moved. */
  883.     double deltaX, deltaY;        /* Amount by which item is to be
  884.                      * moved. */
  885. {
  886.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  887.     double *coordPtr;
  888.     int i;
  889.  
  890.     for (i = 0, coordPtr = polyPtr->coordPtr; i < polyPtr->numPoints;
  891.         i++, coordPtr += 2) {
  892.     *coordPtr += deltaX;
  893.     coordPtr[1] += deltaY;
  894.     }
  895.     ComputePolygonBbox(canvas, polyPtr);
  896. }
  897.  
  898. /*
  899.  *--------------------------------------------------------------
  900.  *
  901.  * PolygonToPostscript --
  902.  *
  903.  *    This procedure is called to generate Postscript for
  904.  *    polygon items.
  905.  *
  906.  * Results:
  907.  *    The return value is a standard Tcl result.  If an error
  908.  *    occurs in generating Postscript then an error message is
  909.  *    left in interp->result, replacing whatever used
  910.  *    to be there.  If no error occurs, then Postscript for the
  911.  *    item is appended to the result.
  912.  *
  913.  * Side effects:
  914.  *    None.
  915.  *
  916.  *--------------------------------------------------------------
  917.  */
  918.  
  919. static int
  920. PolygonToPostscript(interp, canvas, itemPtr, prepass)
  921.     Tcl_Interp *interp;            /* Leave Postscript or error message
  922.                      * here. */
  923.     Tk_Canvas canvas;            /* Information about overall canvas. */
  924.     Tk_Item *itemPtr;            /* Item for which Postscript is
  925.                      * wanted. */
  926.     int prepass;            /* 1 means this is a prepass to
  927.                      * collect font information;  0 means
  928.                      * final Postscript is being created. */
  929. {
  930.     char string[100];
  931.     PolygonItem *polyPtr = (PolygonItem *) itemPtr;
  932.  
  933.     /*
  934.      * Fill the area of the polygon.
  935.      */
  936.  
  937.     if (polyPtr->fillColor != NULL) {
  938.     if (!polyPtr->smooth) {
  939.         Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  940.             polyPtr->numPoints);
  941.     } else {
  942.         TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
  943.             polyPtr->numPoints);
  944.     }
  945.     if (Tk_CanvasPsColor(interp, canvas, polyPtr->fillColor) != TCL_OK) {
  946.         return TCL_ERROR;
  947.     }
  948.     if (polyPtr->fillStipple != None) {
  949.         Tcl_AppendResult(interp, "eoclip ", (char *) NULL);
  950.         if (Tk_CanvasPsStipple(interp, canvas, polyPtr->fillStipple)
  951.             != TCL_OK) {
  952.         return TCL_ERROR;
  953.         }
  954.         if (polyPtr->outlineColor != NULL) {
  955.         Tcl_AppendResult(interp, "grestore gsave\n", (char *) NULL);
  956.         }
  957.     } else {
  958.         Tcl_AppendResult(interp, "eofill\n", (char *) NULL);
  959.     }
  960.     }
  961.  
  962.     /*
  963.      * Now draw the outline, if there is one.
  964.      */
  965.  
  966.     if (polyPtr->outlineColor != NULL) {
  967.     if (!polyPtr->smooth) {
  968.         Tk_CanvasPsPath(interp, canvas, polyPtr->coordPtr,
  969.         polyPtr->numPoints);
  970.     } else {
  971.         TkMakeBezierPostscript(interp, canvas, polyPtr->coordPtr,
  972.         polyPtr->numPoints);
  973.     }
  974.  
  975.     sprintf(string, "%d setlinewidth\n", polyPtr->width);
  976.     Tcl_AppendResult(interp, string,
  977.         "1 setlinecap\n1 setlinejoin\n", (char *) NULL);
  978.     if (Tk_CanvasPsColor(interp, canvas, polyPtr->outlineColor)
  979.         != TCL_OK) {
  980.         return TCL_ERROR;
  981.     }
  982.     Tcl_AppendResult(interp, "stroke\n", (char *) NULL);
  983.     }
  984.     return TCL_OK;
  985. }
  986.